#include "program.h"
#include "shader.h"

bool
eTB_Program::Bind (void)
{
  glUseProgram (handle_);

  if (glGetError () != GL_NO_ERROR)
    return false;

  return true;
}

bool
eTB_Program::Unbind (void)
{
  glUseProgram (NULL);

  /* TODO: Check if this program is currently bound before unbinding... */

  return true;
}

bool
eTB_Program::AttachShader (eTB_Shader* pShader)
{
  if (! pShader)
    return NULL;

  eTB_Shader** ppShader = NULL;

  switch (pShader->GetType ()) {
    case eTB_Shader::Vertex:
      ppShader = &vertex_shader_;
      break;
    case eTB_Shader::Pixel:
      ppShader = &pixel_shader_;
      break;
    default:
      /* Only Vertex and Pixel for now... */
      return false;
  }

  glAttachShader (handle_, pShader->handle_);

  if (glGetError () != GL_NO_ERROR)
    return false;

  *ppShader = pShader;

  return true;
}

bool
eTB_Program::Link (void)
{
  glLinkProgram (handle_);

  if (glGetError () != GL_NO_ERROR)
    return false;

  GLint link_status = GL_FALSE;
  glGetProgramiv (handle_, GL_LINK_STATUS, &link_status);

  if (link_status == GL_FALSE)
    return false;

  return true;
}

eTB_Shader*
eTB_Program::GetShader (eTB_Shader::Type type) {
  switch (type) {
    case eTB_Shader::Vertex:
      return vertex_shader_;
    case eTB_Shader::Pixel:
      return pixel_shader_;
    default:
      /* Only Vertex / Pixel Shaders for Now... */
      return NULL;
  }
}

eStringA
eTB_Program::GetLog (void)
{
  GLint string_len;
  glGetProgramiv (handle_, GL_INFO_LOG_LENGTH, &string_len);

  char* log = new char [string_len + 1];

  glGetProgramInfoLog (handle_, string_len + 1, NULL, log);

  eStringA log_str (log);

  delete [] log;

  return log_str;
}


eTB_Program*
eTB_ProgramFactory::createProgram (const char* szName)
{
  eTB_Program* pProgram = new eTB_Program (szName);

  return pProgram;
}

GLuint
eTB_Program::GetUniform (const char* szName)
{
  return glGetUniformLocation (handle_, szName);
}